var http = require( 'http' );
var express = require( 'express' );
var app = express();
var manager = require( "./manager.js" );
var nodemailer = require( "nodemailer" );
var moment = require( 'moment' );
var crypto = require( 'crypto' );
var request = require( 'request' );
var async = require('async');

var smtpTransport = nodemailer.createTransport( "SMTP", {
    service: "Gmail",
    auth: {
        user: "ust.nutrition@gmail.com",
        pass: "love!sung"
    }
});

var instance = new manager();
var port = process.env.port || 5000;
var sync = "http://localhost:4985/";

app.post( "/api", express.json(), instance.process.bind( instance ) );
app.use( "/res", express.static( __dirname + "/res" ) );

app.get( "/auth", function(req, res) {
    var email = req.param("email");
    var code = req.param("code");
    res.send("<html><body><a href=\"ustnutrition://" + email + "/" + code + "\">Click Here to validate</a></body></html>");
});


var email = /^([A-Z._]+)@[A-Z.]*ust\.hk$/i;
var users = {};

var serverKey = "ust.nutrition:love!sung";
{
    var sha256 = crypto.createHash("sha256");
    sha256.update("ust.nutrition:love!sung");
    serverKey = sha256.digest('buffer');
}

var r = require('randgen');

var datas =
[
    { name: "Kim Sung", score: 99 },
    { name: "Ming", score: 98 },
    { name: "Tommy", score: 98.1 },
    { name: "Darren", score: 95 },
    { name: "Peter", score: 93 },
    { name: "Macro", score: 91 },
    { name: "Michael", score: 87 },
    { name: "Jeremy", score: 87.5 },
    { name: "Tony", score: 86.7 },
    { name: "Oscar", score: 86.1 },
];

for(var i = 0; i < 300; i++) {
    var s;
    while((s = r.rnorm(50, 25)) > 86 || s < 0);
    datas.push({name: "Person " + i, score: s});
}

instance
    .command( "login" )
    .arg( "email", email )
    .run( function ( callback, data, result ) {
        var itsc = data.email.match(email)[1];
        var user = users[itsc];
        if (!user)
            user = users[itsc] = {};

        user.code = crypto.randomBytes(4).toString( 'hex' );
        user.lastLogin = Date.now();
        var mailOptions = {
            from: "UST Nutrition <ust.nutrition@gmail.com>",
            to: data.email,
            subject: "Login Request from UST Nutirtion",
            html: "Your validation code is: <b>" + user.code + "</b>" // html body
        };
        smtpTransport.sendMail( mailOptions, function ( error, response ) {
            if ( error ) {
                callback( error );
                console.log( error );
            } else {
                result.msg = "An email has been sent to your email account. Please use the validation code to login.";
                callback();
            }
        });
    })
    .command( "validate" )
    .arg( "email", email )
    .arg( "code", manager.binary( 4 ) )
    .run( function ( callback, data, result ) {
        var itsc = data.email.match(email)[1];
        var user = users[itsc];
        if(!user) {
            result.code = -100;
            result.msg = "The user is invalid or the validation code is expired!";
            callback();
        }
        else {
            var loginTime = moment( user.lastLogin );
            var now = moment( Date.now() );
            var diff = now.diff( loginTime, 'minutes' );
            if(diff > 15 || user.code != data.code.toString('hex')) {
                result.code = -100;
                result.msg = "The user is invalid or the validation code is expired!";
                callback();
            } else {
                var hmac = crypto.createHmac("sha1", serverKey);
                hmac.update(itsc);
                var pw = hmac.digest("hex");

                var userObj = {
                    password: pw,
                    admin_channels: ["public", itsc]
                };

                async.eachSeries(["foods", "restaurants", "records"], function(key, callback) {
                    var url = sync + key + "/_user/" + itsc;
                    console.log("checking permission for " + itsc + " in bucket " + key);
                    request.get({url: url}, function(err, req, body) {
                        if(err) {
                            console.log(err);
                            callback(err);
                        } else {
                            console.log(body);
                            body = JSON.parse(body);
                            if(body.error) {
                                console.log("adding permission for " + itsc + " in bucket " + key);
                                request.put({url: url, json: userObj}, function(err, req, body) {
                                    if(err) {
                                        console.log(err);
                                        callback(err);
                                    } else {
                                        callback();
                                    }
                                });
                            } else {
                                console.log("permission for " + itsc + " in bucket " + key + " already exists");
                                callback();
                            }
                        }
                    });
                }, function(err) {
                    if(err) {
                        result.code = -101;
                        result.msg = "Internal server error";
                    } else {
                        result.data = pw;
                        result.msg = "Login success!";
                        delete users[itsc];
                    }
                    callback();
                });
            }
        }
    })
    .command( "rate" )
    .arg( "food", manager.string() )
    .arg( "score", manager.int() )
    .run( function ( callback, data, result ) {
        if(data.score < 0 || data.score > 10) {
            result.code = -200;
            result.msg = "The rating is invalid!";
            callback();
        } else {
            var url = sync + "foods/" + data.food;
            request.get({url: url}, function(err, req, body) {
                if(err) {
                    result.code = -201;
                    result.msg = "Internal server error";
                    callback();
                }
                else {
                    body = JSON.parse(body);
                    if(body.error) {
                        result.code = -202;
                        result.msg = "The food id is invalid!";
                        callback();
                    } else {
                        if(!body.score)
                            body.score = 0;
                        if(!body.scoreNum)
                            body.scoreNum = 0;
                        body.score += data.score;
                        body.scoreNum++;

                        request.put({url: url, json:body}, function(err, req, body) {
                            if(err) {
                                result.code = -201;
                                result.msg = "Internal server error";
                            } else {
                                if(body.error) {
                                    result.code = -201;
                                    result.msg = "Internal server error";
                                } else {
                                    result.code = 0;
                                    result.msg = "Your rating is successfully submitted";
                                }
                                callback();
                            }
                        });
                    }
                }
            } );
        }
    })
    .command("rank")
    .arg("user", manager.string(true))
    .arg("name", manager.string(true))
    .arg("score", manager.int(true))
    .run( function ( callback, data, result ) {
        //hard code rank
        var tdatas = [];
        for(var i = 0; i < datas.length; i++)
            tdatas.push(datas[i]);

        if(data.user) {
            var m = {name: data.name, score: data.score};
            tdatas.push(m);
        }

        tdatas.sort(function(a,b) { return b.score-a.score;});

        result.data = tdatas.slice(0, 10);
        if(data.user)
            result.rank = tdatas.indexOf(m) + 1;

        callback();

    })
    .command("statistics")
    .arg("score", manager.int(true))
    .run( function ( callback, data, result ) {
        //hard code statistic
        var tdatas = [];
        for(var i = 0; i < datas.length; i++)
            tdatas.push(datas[i]);

        if(data.score) {
            var m = {score: data.score};
            tdatas.push(m);
        }

        var r = [];
        for(var i = 0; i < 20; i++) {
            r.push({x:i*5, y:0});
        }
        for(var i = 0; i < tdatas.length; i++)
        {
            var s = Math.floor(tdatas[i].score / 5);
            if(s < 0) s = 0;
            if(s >= 20) s = 19;
            r[s].y++;
        }

        result.data = r;
        callback();
    });


app.listen( port );

